package com.gitee.chili.leisure.handler;

import com.gitee.chili.leisure.ResponseCode;
import com.gitee.chili.leisure.RoomManager;
import com.gitee.chili.leisure.core.Handler;
import com.gitee.chili.leisure.core.NettyHandler;
import com.gitee.chili.leisure.domain.BallotBox;
import com.gitee.chili.leisure.game.MahjongPlayer;
import com.gitee.chili.leisure.game.RoomDetail;
import com.gitee.chili.leisure.message.*;
import com.gitee.chili.leisure.model.MahjongModel;
import com.gitee.chili.leisure.model.MessageCmdEnum;
import com.gitee.chili.leisure.util.AuxiliaryChannel;
import com.gitee.chili.leisure.util.AuxiliaryRoom;
import com.gitee.chili.leisure.util.Connection;
import com.gitee.chili.leisure.util.Utils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;

/**
 * 消息处理器
 * <p>
 * 这里可以处理获取到消息后的逻辑，并且可以依赖注入
 *
 * @author week solider
 * @since 2020.08.31
 */
@Slf4j
@SuppressWarnings("unused")
@NettyHandler
public class NettyHandlers {

    @Autowired
    private MessageTransferHandler messageTransferHandler;


    @Handler(cmd = MessageCmdEnum.Command.HEARTBEAT, desc = "心跳处理")
    public void heartbeat(Heartbeat heartbeat) {
        heartbeat.writeFlush();
    }


    @Handler(cmd = MessageCmdEnum.Command.LOGIN, desc = "登录")
    public void login(Login login) {
        // 写回登录消息
        login.writeFlush();
        // 断线重连
        login.reconnection();
    }


    @Handler(cmd = MessageCmdEnum.Command.LOGOUT, desc = "登出")
    public void logout(Logout logout) {
        logout.writeFlush();
    }


    @Handler(cmd = MessageCmdEnum.Command.CREATE_FRIEND_ROOM, desc = "创建好友房")
    public void createFriendRoom(CreateFriendRoom createFriendRoom) {
        messageTransferHandler.roomTimeoutTask(createFriendRoom.getRoomNum());
        Connection.broadcaster().notify(createFriendRoom.getRoomNum(), createFriendRoom.getPacket());
    }


    @Handler(cmd = MessageCmdEnum.Command.ENTRY_ROOM, desc = "进入房间")
    public void createFriendRoom(EntryRoom entryRoom) {
        Connection.broadcaster().notify(entryRoom.getRoomNum(), entryRoom.getPacket());
    }


    @Handler(cmd = MessageCmdEnum.Command.READY_GAME, desc = "玩家准备")
    public void ready(Ready ready) {
        // 自己不需要接收
        Connection.broadcaster().notify(ready.getRoomNum(), ready.getMemberId(), ready.getPacket());

        // 是否需要开始游戏
        if (ready.isNeedStart()) {
            try {
                messageTransferHandler.start(ready.getRoomNum());
            } catch (Exception e) {
                AuxiliaryChannel.errorMessage(ready.getChannel(), ready.getCommand(), ResponseCode.FAIL);
            }
        }
    }


    @Handler(cmd = MessageCmdEnum.Command.END_CHANGING, desc = "换三张")
    public void exchangeThree(ExchangeThree exchange) {
        if (exchange.isOver()) {
            exchange.writeFlush();
            // 进入定缺流程
            Connection.broadcaster().notify(exchange.getRoomNum(), AuxiliaryRoom.launchUseless());
            // 开启定缺定时任务
            RoomManager.obtain(exchange.getRoomNum()).getPlayers()
                    .forEach(p -> messageTransferHandler.uselessTask(exchange.getRoomNum(), (MahjongPlayer) p));
        }
    }


    @Handler(cmd = MessageCmdEnum.Command.OPERATE_RESULT, desc = "玩家操作结果(房间内)")
    public void memberOperate(MemberOperate operate) {

        // 清除玩家操作状态
        messageTransferHandler.clearOperateStatue(operate.getPlayer());

        // 如果不是出牌 还要等待其他玩家的操作
        // 可能有一种情况是 有人能杠、碰  但有玩家可以胡 此时的杠和碰是无效的
        if (operate.getOperateType().equals(MahjongModel.OptionsType.DISCARD)) {
            Connection.broadcaster().notify(operate.getRoomNum(), operate.getPacket());
        }

        if (operate.getOperateType().equals(MahjongModel.OptionsType.PASS)) {
            Connection.broadcaster().send(operate.getRoomNum(), operate.getMemberId(), operate.getPacket());
        }

        // 检查是否还有人需要操作
        messageTransferHandler.checkOperate(operate.getRoomNum(), operate.getOperateResult(), operate.getPacket());
    }


    @Handler(cmd = MessageCmdEnum.Command.END_USELESS, desc = "定缺")
    public void uselessFinish(Useless useless) {
        if (useless.isOver()) {
            // 广播定缺信息
            Connection.broadcaster().notify(useless.getRoomNum(), useless.getPacket());

            RoomDetail roomDetail = RoomManager.obtain(useless.getRoomNum());

            // 获取庄家信息 -> 推送庄家出牌消息
            Utils.accept(roomDetail.getPlayers(), p -> p.getPosition() == roomDetail.getBankerSeat(),
                    messageTransferHandler::notifiesDiscard);
        }
    }


    @Handler(cmd = MessageCmdEnum.Command.READY_HAND, desc = "听牌")
    public void leaveRoom(ReadyHand readyHand) {
        readyHand.writeFlush();
    }


    @Handler(cmd = MessageCmdEnum.Command.LEAVE_ROOM, desc = "玩家退出房间")
    public void leaveRoom(LeaveRoom leaveRoom) {
        Connection.broadcaster().notify(leaveRoom.getRoomNum(), leaveRoom.getPacket());
    }


    @Handler(cmd = MessageCmdEnum.Command.LEAVE_ROOM, desc = "解散房间")
    public void dissolvedRoom(DissolvedRoom dissolvedRoom) {
        Connection.broadcaster().notify(dissolvedRoom.getRoomNum(), dissolvedRoom.getPacket());
    }


    @Handler(cmd = MessageCmdEnum.Command.LEAVE_ROOM, desc = "投票解散房间")
    public void dissolvedRoom(VoteDissolvedRoom voteDissolvedRoom) {
        Long roomNum = voteDissolvedRoom.getRoomNum();
        messageTransferHandler.voteDissolvedRoomTask(roomNum);
        Connection.broadcaster().notify(roomNum, voteDissolvedRoom.getPacket());
    }


    @Handler(cmd = MessageCmdEnum.Command.LEAVE_ROOM, desc = "玩家投票")
    public void dealVote(VoteProcessor voteProcessor) {
        Long roomNum = voteProcessor.getRoomNum();

        BallotBox ballotBox = BallotBox.builder()
                .memberId(voteProcessor.getMemberId().toString())
                .roomNum(voteProcessor.getRoomNum().toString())
                .isAgree(voteProcessor.isAgree())
                .build();
        // 记录投票信息
        messageTransferHandler.recordVote(ballotBox);
        // 取消定时任务
        messageTransferHandler.cancelVoteDissolvedTask(roomNum);
        // 广播投票信息
        Connection.broadcaster().notify(roomNum, voteProcessor.getPacket());
    }

}
